package komorki;
import automaty.Automat;
import automaty.AutomatBinarny;
import automaty.AutomatDrapeznik;
import okna.Plansza;
import stany.BinaryState;
import stany.PredatorState;
import stany.Tryby;



public class ManagerKomorek {
	private static ManagerKomorek manager;
	private Komorka[][] komorki;
	private Automat automat;
	//11x17 tak naprawde
	public static  int maxRow = 10;
	public static  int maxColumn = 10;
	private float speed;
	private boolean runnning = false;
	private Thread watek;
	private Plansza plansza;
	private boolean krok = false;
	
	private ManagerKomorek(Plansza plansza) {
		super();
		int x,y;
		x = y = 0;
		speed = 0.1f;
		komorki = new Komorka[maxRow][maxColumn];
		
		//tworzymy komorki
		for(int i = 0; i < maxRow ; i++){
			for(int j = 0; j < maxColumn; j++){
				komorki[i][j] = new Komorka(x, y,i,j);	
				x += 30;
			}
			x = 0;
			y += 30;
		}
		this.plansza = plansza;
		plansza.setKomorki(komorki);
		
		
		//domyslnie automat binarny
		automat = new AutomatBinarny(maxRow, maxColumn, komorki, new BinaryState());
	}
	private ManagerKomorek(Plansza plansza,Automat au) {
		this(plansza);
		automat = au;
	}
	
	public Komorka[][] getKomorki(){
		return komorki;
	}
	
	public Komorka getKomorka(int row, int column){
		return komorki[row][column];
	}
	
	public static ManagerKomorek manager(Plansza plansza){
		manager = new ManagerKomorek(plansza);
		//budujemy macierz sasedzwa dla kazdej komorki
		
		return manager;
	}
	public static ManagerKomorek manager(Plansza plansza,Automat au){
		manager = new ManagerKomorek(plansza,au);
		//budujemy macierz sasedzwa dla kazdej komorki
		
		return manager;
	}
	
	public Automat getAutomat(){
		return automat;
	}
	
	public void buildNeighbourhoodStruct(){
		for(int i = 0; i < maxRow ; i++)
			for(int j = 0; j < maxColumn; j++)
				manager.komorki[i][j].buildNeighbourhood();
	}
	public static ManagerKomorek getManager(){
		if(manager != null)
			return manager;
		return null;
	}
	 public void  stop(){
		runnning = false;
		try {
			if(watek != null){
				watek.join();
				watek = null;
			}
		} catch (InterruptedException e) {
			System.out.println("Pzerwano oczekiwanie!");
		}
	}
	
	 public void setKrok(boolean k){
		 stop();
		 krok = k;
		 start();
	 }
	
	public void random(){
		if(runnning){
			stop();
			automat.random();
			plansza.repaint();
			start();
		}else{
			automat.random();
			plansza.repaint();
		}
	}
	
	public void clean(){
		stop();
		automat.clean();
		plansza.repaint();
	}
	
	public void start(){
		runnning = true;
		if(watek == null){
			watek = new Thread(new Watek());
			watek.start();
		}
		
	}

	public void setSpeed(float speed) {
		this.speed = speed;
		if(!runnning)
			start();
	}
	
	
	private void validateAll(){
		for(int i = 0; i < maxRow; i++)
			for(int j = 0; j < maxColumn; j++)
				komorki[i][j].validate();
	}
	public void setAutomat(Automat automat) {
		stop();
		this.automat = automat;
		automat.clean();
		validateAll();
		plansza.changeColors(automat.getState().getAvailableColors(), automat.getState().getDescriptions());
		plansza.repaint();
		
		
	}
	
	public void changeAutomat(String name){
		Tryby tryb = Tryby.valueOf(name);
		Automat au = null;
		switch(tryb){
		case BINARNY:
			 au = new AutomatBinarny(maxRow, maxColumn, komorki, new BinaryState());
			 break;
		case DRAPIEZNIK:
			au = new AutomatDrapeznik(maxRow, maxColumn, komorki, new PredatorState());
		}
		if(au != null)
			setAutomat(au);
	}
	class Watek implements Runnable{

		@Override
		public void run() {
			while(runnning){
				synchronized(this){
					automat.changeState();
					validateAll();
					plansza.repaint();
					try {
						wait((long) (1000 * speed));
					} catch (InterruptedException e) {
						System.out.println("Przerwano wait");
					}
					if(krok){
						krok = false;
						runnning = false;
						watek = null;
					}
				}
			}
			
			
		}
		
	}
	
}
